home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 March / Macworld (1998-03) (Disk 1).dmg / Shareware World / Info / For Developers / GhostScript 5.10 / MacGS-510 / files / gs_ttf.ps < prev    next >
Text File  |  1997-08-04  |  15KB  |  462 lines

  1. %    Copyright (C) 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2. % This file is part of Aladdin Ghostscript.
  3. % Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  4. % or distributor accepts any responsibility for the consequences of using it,
  5. % or for whether it serves any particular purpose or works at all, unless he
  6. % or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  7. % License (the "License") for full details.
  8. % Every copy of Aladdin Ghostscript must include a copy of the License,
  9. % normally in a plain ASCII text file named PUBLIC.  The License grants you
  10. % the right to copy, modify and redistribute Aladdin Ghostscript, but only
  11. % under certain conditions described in the License.  Among other things, the
  12. % License requires that the copyright notice and this notice be preserved on
  13. % all copies.
  14.  
  15. % Support code for direct use of TrueType fonts.
  16. % (Not needed for Type 42 fonts.)
  17.  
  18. % ---------------- Font loading machinery ---------------- %
  19.  
  20. % Augment the FONTPATH machinery so it recognizes TrueType fonts.
  21.  
  22. /.scanfontheaders where        % only defined if DISKFONTS is recognized
  23.  { pop
  24.    /.scanfontheaders [ .scanfontheaders aload pop (\000\001\000\000*) ] def
  25.  }
  26. if
  27. /.findnonttfontvalue /.findfontvalue load def
  28. /.findfontvalue        % <file> <key> .findfontvalue <value> true
  29.             % <file> <key> .findfontvalue false
  30.             % Closes the file in either case.
  31.  { 1 index read pop 2 index 1 index unread 0 eq
  32.     {        % If this is a font at all, it's a TrueType font.
  33.       dup /FontType eq
  34.        { pop closefile 42 true }
  35.        { dup /FontName eq
  36.       { pop .findttfontname }
  37.       { pop closefile false }
  38.      ifelse
  39.        }
  40.       ifelse
  41.     }
  42.     {        % Not a TrueType font.
  43.       .findnonttfontvalue
  44.     }
  45.    ifelse
  46.  } bind def
  47. /.findttfontname    % <file> .findttfontname <fname> true
  48.             % <file> .findttfontname false
  49.             % Closes the file in either case.
  50.  { .loadttfonttables
  51.    (name) findtableentry
  52.     { dup 8 getu32 f exch setfileposition
  53.       12 getu32 string f exch readstring pop
  54.       6 findname
  55.     }
  56.     { false
  57.     }
  58.    ifelse
  59.    f closefile end end
  60.  } bind def
  61.  
  62. % Load a font file that might be a TrueType font.
  63.  
  64. /.loadnonttfontfile /.loadfontfile load def
  65. /.loadfontfile        % <file> .loadfontfile -
  66.  { dup read pop 2 copy unread 0 eq
  67.     {        % If this is a font at all, it's a TrueType font.
  68.       .loadttfont pop
  69.     }
  70.     {        % Not a TrueType font.
  71.       .loadnonttfontfile
  72.     }
  73.    ifelse
  74.  } bind def
  75.  
  76. % ---------------- Automatic Type 42 generation ---------------- %
  77.  
  78. % Load a TrueType font from a file as a Type 42 PostScript font.
  79. % The thing that makes this really messy is the handling of encodings.
  80. % There are 3 interacting tables that affect the encoding:
  81. %    'cmap' provides multiple maps from character codes to glyph indices
  82. %    'glyf' maps glyph indices to outlines
  83. %    'post' maps glyph indices to glyph names (if present)
  84. % What we need to get out of this is:
  85. %    Encoding mapping character codes to glyph names
  86. %      (the composition of cmap and post)
  87. %    CharStrings mapping glyph names to glyph indices
  88. %      (the inverse of post)
  89. % If the post table is missing, we have to take a guess based on the cmap
  90. % table.
  91.  
  92. /.loadttfontdict mark
  93. /orgXUID 107 def    % Aladdin Enterprises organization XUID
  94. /maxstring 65500 def    % maximum length of a PostScript string
  95.  
  96. % Define the Macintosh standard mapping from characters to glyph indices.
  97. /MacRomanEncoding dup .findencoding def
  98. /MacGlyphEncoding mark
  99.     /.notdef /.null /CR
  100. MacRomanEncoding 32 95 getinterval aload pop
  101. MacRomanEncoding 128 45 getinterval aload pop
  102. % 143
  103.     /notequal /AE
  104.     /Oslash /infinity /plusinus /lessequal /greaterequal
  105.     /yen /mu1 /partialdiff /summation /product
  106.     /pi /integral /ordfeminine /ordmasculine /Ohm
  107.     /ae /oslash /questiondown /exclamdown /logicalnot
  108.     /radical /florin /approxequal /increment /guillemotleft
  109.     /guillemotright /ellipsis /nbspace
  110. MacRomanEncoding 203 12 getinterval aload pop
  111.     /lozenge
  112. MacRomanEncoding 216 24 getinterval aload pop
  113.     /applelogo
  114. MacRomanEncoding 241 7 getinterval aload pop
  115.     /overscore
  116. MacRomanEncoding 249 7 getinterval aload pop
  117. % 226
  118.     /Lslash /lslash /Scaron /scaron
  119.     /Zcaron /zcaron /brokenbar /Eth /eth
  120.     /Yacute /yacute /Thorn /thorn /minus
  121.     /multiply /onesuperior /twosuperior /threesuperior /onehalf
  122.     /onequarter /threequarters /franc /Gbreve /gbreve
  123.     /Idot /Scedilla /scedilla /Cacute /cacute
  124.     /Ccaron /ccaron /dmacron
  125. /packedarray where
  126.  { pop counttomark packedarray exch pop }
  127.  { ] readonly }
  128. ifelse def
  129.  
  130. % Procedures
  131. /getu16            % <string> <index> getu16 <integer>
  132.  { 2 copy get 8 bitshift 3 1 roll 1 add get add
  133.  } bind def
  134. /gets16            % <string> <index> gets16 <integer>
  135.  { getu16 16#8000 xor 16#8000 sub
  136.  } bind def
  137. /getu32            % <string> <index> getu32 <integer>
  138.  { 2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add
  139.  } bind def
  140. /gets32            % <string> <index> gets32 <integer>
  141.  { getu32 dup 16#7fffffff gt { 4 { 16#40000000 sub } repeat } if
  142.  } bind def
  143. /getrange        % <offset> <length> getrange <string>
  144.             % Free variables: sfnts
  145.  { () sfnts
  146.     {        % Stack: offset length () sfnt
  147.       dup length 4 index gt { exch pop exit } if
  148.       4 -1 roll exch length sub 3 1 roll
  149.     }
  150.    forall 3 1 roll getinterval
  151.  } bind def
  152. /findtableentry        % <name4> findtableentry <tableentry> true
  153.             % <name4> findtableentry false
  154.             % Free variables: tables
  155.  { false 0 16 tables length 16 sub
  156.     {        % Stack: name4 false toffset
  157.       tables 1 index 4 getinterval 3 index eq
  158.        { tables exch 16 getinterval
  159.      exch pop exch true exit
  160.        }
  161.       if pop
  162.     }
  163.    for exch pop
  164.  } bind def
  165. /findtable        % <name4> findtable <table> true
  166.             % <name4> findtable false
  167.             % Free variables: tables
  168.  { findtableentry
  169.     { dup 8 getu32 exch 12 getu32 getrange true }
  170.     { false }
  171.    ifelse
  172.  } bind def
  173. /findname        % <nametable> <nameid> findname <string> true
  174.             % <nametable> <nameid> findname false
  175.  { false 3 1 roll 0 1 3 index 2 getu16 1 sub
  176.     {        % Stack: false table id index
  177.       12 mul 6 add 2 index exch 12 getinterval
  178.       dup 6 getu16 2 index eq
  179.        {    % We found the name we want.
  180.      exch pop
  181.         % Stack: false table record
  182.      dup 10 getu16 2 index 4 getu16 add
  183.      1 index 8 getu16 4 -1 roll 3 1 roll getinterval exch
  184.         % Stack: false string record
  185.         % Check for 8- vs. 16-bit characters.
  186.      is2byte { string2to1 } if true null 4 -1 roll exit
  187.        }
  188.       if pop
  189.     }
  190.    for pop pop
  191.  } bind def
  192. /is2byte        % <namerecord> is2byte <bool>
  193.  { dup 0 getu16
  194.     { { pop true }        % Apple Unicode
  195.       { pop false }        % Macintosh Script manager
  196.       { 1 getu16 1 eq }        % ISO
  197.       { 1 getu16 1 eq }        % Microsoft
  198.     }
  199.    exch get exec
  200.  } bind def
  201. /string2to1        % <string2> string2to1 <string>
  202.  { dup length 2 idiv string dup
  203.    0 1 3 index length 1 sub
  204.     { 3 index 1 index 2 mul 1 add get put dup }
  205.    for pop exch pop
  206.  } bind def
  207. /cmapformats mark
  208.         % Each procedure in this dictionary is called as follows:
  209.         %    -mark- encodingtable <<proc>> -mark- glyphindices...
  210.   0        % Apple standard 1-to-1 mapping.
  211.     { 6 256 getinterval { } forall
  212.     } bind
  213.   4        % Microsoft/Adobe segmented mapping.
  214.     { /etab exch def
  215.       /nseg2 etab 6 getu16 def
  216.       14 /endc etab 2 index nseg2 getinterval def
  217.         % The Apple TrueType documentation omits the 2-byte
  218.         % 'reserved pad' that follows the endCount vector!
  219.       2 add
  220.       nseg2 add /startc etab 2 index nseg2 getinterval def
  221.       nseg2 add /iddelta etab 2 index nseg2 getinterval def
  222.       nseg2 add /idroff etab 2 index nseg2 getinterval def
  223.         % The following hack allows us to properly handle
  224.         % idiosyncratic fonts that start at 0xf000:
  225.       /firstcode startc 0 getu16 16#ff00 and def
  226.       pop 0 2 nseg2 3 sub
  227.        { /i2 exch def
  228.          /scode startc i2 getu16 def
  229.      counttomark scode firstcode sub 256 min exch sub 0 max { 0 } repeat
  230.      /ecode endc i2 getu16 def
  231.      /delta iddelta i2 getu16 def
  232.      idroff i2 getu16 dup 0 eq
  233.       { pop scode 1 ecode { delta add 65535 and } for
  234.       }
  235.       {    % The +2 is for the 'reserved pad'.
  236.         /gloff exch 14 nseg2 3 mul add 2 add i2 add add def
  237.         0 1 ecode scode sub
  238.          { 2 mul gloff add etab exch getu16
  239.            dup 0 ne { delta add 65535 and } if
  240.          }
  241.         for
  242.       }
  243.      ifelse
  244.        }
  245.       for
  246.     } bind
  247.   6        % Single interval lookup.
  248.     { dup 6 getu16 { 0 exch } repeat
  249.       dup 8 getu16 0 exch 1 exch 1 sub
  250.        { 2 mul 10 add 2 copy getu16 exch pop exch }
  251.       repeat pop
  252.     } bind
  253. .dicttomark readonly def        % cmapformats
  254. /cmaparray        % <cmaptab> cmaparray -mark- <glyphs> ...
  255.  { mark exch dup 0 getu16 cmapformats exch .knownget
  256.     { exec }
  257.     { (Can't handle format ) print 0 getu16 = flush
  258.       0 1 255 { } for
  259.     }
  260.    ifelse
  261.  } bind def
  262. /postformats mark
  263.         % Each procedure in this dictionary is called as follows:
  264.         %    posttable <<proc>> glyphencoding
  265.   16#00020000    % Detailed map, required by Microsoft fonts.
  266.     { /postglyphs exch def
  267.       postglyphs 32 getu16 /numglyphs exch def
  268.       /glyphnames numglyphs 2 mul 34 add def
  269.       [ 0 1 numglyphs 1 sub
  270.        { 2 mul 34 add postglyphs exch getu16
  271.      dup 258 lt
  272.       { MacGlyphEncoding exch get
  273.       }
  274.       { 258 sub glyphnames exch
  275.          { postglyphs 1 index get 1 add add }
  276.         repeat
  277.         1 add postglyphs exch 2 copy 1 sub get getinterval cvn
  278.       }
  279.      ifelse
  280.        }
  281.       for ]
  282.     } bind
  283. .dicttomark readonly def        % postformats
  284. .dicttomark readonly def        % .loadttfontdict
  285. /.loadttfonttables    % <file> .loadttfonttables -
  286.             % Pushes .loadttfontdict & scratch dict on d-stack,
  287.             % defines f, offsets, tables
  288.  { .loadttfontdict begin
  289.    40 dict begin
  290.    /f exch def
  291.    /offsets f 12 string readstring pop def
  292.    /tables f offsets 4 getu16 16 mul string readstring pop def
  293.  } bind def
  294. /.readsfnts0 {        % <len0> .readsfnts0 <string>
  295.    dup string
  296.      dup 0 offsets putinterval
  297.      dup offsets length tables putinterval
  298.      dup offsets length tables length add
  299.             % Stack: len0 str str off+tab
  300.        3 index 1 index sub getinterval
  301.        f exch dup length 0 ne { readstring } if pop pop
  302.    exch pop
  303. } bind def
  304. /.dividesfnts {        % <length> .dividesfnts -
  305.    (glyf) findtableentry pop
  306.    dup 8 getu32 /len0 exch def
  307.    12 getu32 /len1 exch def
  308.    len0 len1 add sub /len2 exch def
  309.    /sfnts [
  310.    len0 .readsfnts0
  311.    len1 dup maxstring gt
  312.     {        % Bad news: we'll have to split the glyfs.
  313.         % Right now we only provide for splitting into 2 parts,
  314.         % but we could generalize this without too much trouble.
  315.       f maxstring string readstring pop
  316.       exch maxstring sub
  317.     }
  318.    if string f exch readstring pop
  319.    len2 0 ne { f len2 string readstring pop } if
  320.    ] def
  321.    /head (head) findtable pop def
  322.    len1 maxstring gt
  323.     {        % Determine where to split the glyfs by scanning loca.
  324.         % The very last entry in loca may be bogus.
  325.         % What a nuisance!
  326.       (loca) findtable pop dup length
  327.       head 50 getu16 0 ne
  328.        {    % 32-bit loca
  329.      8 sub -4 0
  330.       { 1 index exch getu32 dup maxstring le { exch pop exit } if pop }
  331.        }
  332.        {    % 16-bit loca
  333.      4 sub -2 0
  334.       { 1 index exch getu16 1 bitshift dup maxstring le { exch pop exit } if pop }
  335.        }
  336.       ifelse for
  337.         % Now the top element of the stack is the length of
  338.         % the first glyf string.
  339.       sfnts 1 get dup 0 3 index getinterval
  340.     sfnts exch 1 exch put
  341.       exch 1 index length 1 index sub getinterval
  342.     sfnts 2 get concatstrings sfnts exch 2 exch put
  343.     }
  344.    if
  345. } bind def
  346. /.makesfnts        % - .makesfnts -
  347.             % Defines head, sfnts
  348.  {        % Find the end of the last table, and also the end of
  349.         % the last table below the 64K mark.
  350.    0 8 16 tables length
  351.     {        % Stack: end toffset
  352.       DEBUG
  353.        { tables 1 index 8 sub 4 getinterval print ( ) print
  354.      tables 1 index getu32 =only ( ) print
  355.      tables 1 index 4 add getu32 =
  356.        }
  357.       if
  358.       tables 1 index getu32 exch tables exch 4 add getu32 add max
  359.     }
  360.    for
  361.    dup maxstring le {
  362.      .readsfnts0
  363.         % Pad to even length if necessary, per Adobe specification.
  364.      dup length 2 mod 0 ne {
  365.        <00> concatstrings
  366.      } if
  367.      1 array astore /sfnts exch def
  368.      /head (head) findtable pop def
  369.    } {
  370.         % If the total length exceeds maxstring, divide the data
  371.         % into 2+n strings: before glyf, glyfs, after glyf
  372.      .dividesfnts
  373.    } ifelse
  374.  } bind def
  375. /.loadttfont        % <file> .loadttfont <type42font>
  376.  { .loadttfonttables
  377.    .makesfnts
  378.    /upem head 18 getu16 def
  379.    (cmap) findtable pop
  380.            % The Apple cmap format is no help in determining the encoding.
  381.         % Look for a Microsoft table.  If we can't find one,
  382.         % just use the first table, whatever it is.
  383.    dup 4 8 getinterval exch        % the default
  384.    0 1 2 index 2 getu16 1 sub
  385.     { 8 mul 4 add 1 index exch 8 getinterval
  386.       dup 0 getu16 3 eq { exch 3 -1 roll pop exit } if pop
  387.     }
  388.    for
  389.         % Stack: subentry table
  390.    /cmapsub 2 index def
  391.    exch 4 getu32 1 index length 1 index sub getinterval
  392.    /cmaptab exch def
  393.         % See if we have PostScript glyph name information.
  394.    /post (post) findtable not { null } if def
  395.    /glyphencoding post null eq
  396.     { MacGlyphEncoding }
  397.     { postformats post 0 getu32 .knownget
  398.        { post exch exec }
  399.        { MacGlyphEncoding }
  400.      ifelse
  401.     }
  402.    ifelse def
  403.    /checksum head 8 getu32 def
  404.    mark
  405.      /FontType 42
  406.      /FontMatrix matrix
  407.      /PaintType 0
  408.      /FontBBox [ 36 2 42 { head exch gets16 upem div } for ]
  409.      (name) findtable
  410.       {        % Find the names from the 'name' table.
  411.     /names exch def
  412.     /FontName names 6 findname not { checksum 16 8 string cvrs } if
  413.     /FontInfo mark
  414.       names 0 findname { /Notice exch } if
  415.       names 1 findname { /FamilyName exch } if
  416.       names 4 findname { /FullName exch } if
  417.       names 5 findname { /Version exch } if
  418.       }
  419.       {        % No name table, fabricate a FontName.
  420.     /FontName checksum 16 8 string cvrs
  421.     /FontInfo mark
  422.       }
  423.      ifelse
  424.         % Stack: /FontInfo mark key1 value1 ...
  425.      post null ne
  426.       { /ItalicAngle post 4 gets32 65536.0 div
  427.     /isFixedPitch post 12 getu32 0 ne
  428.     /UnderlinePosition post 8 gets16 upem div
  429.     /UnderlineThickness post 10 gets16 upem div
  430.       }
  431.      if
  432.      counttomark 0 ne
  433.       { .dicttomark }
  434.       { pop pop }
  435.      ifelse
  436.      /Encoding
  437.        cmaptab cmaparray
  438.        counttomark array astore { glyphencoding exch get } forall
  439.        counttomark 256 sub dup 0 ge
  440.     { { pop } repeat }
  441.     { neg { /.notdef } repeat }
  442.        ifelse ]
  443.         % Until we can compute the MD5 fingerprint,
  444.         % just use the precomputed checksum.
  445.      /XUID [orgXUID 42 checksum]
  446.      /CharStrings glyphencoding dup length dict
  447.        0 1 3 index length 1 sub
  448.     {    % Stack: glyphencoding dict index
  449.       2 index 1 index get 2 index 1 index known
  450.        { pop pop }
  451.        { 2 index exch 3 -1 roll put }
  452.       ifelse
  453.     }
  454.        for exch pop readonly
  455.      /sfnts sfnts
  456.    .dicttomark
  457.    end end dup /FontName get exch definefont
  458.  } bind def
  459.